#ifndef __H_TSTRING__
#define __H_TSTRING__

#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include <vector>
#include <algorithm>

#include <scoped_ptr.h>

#ifdef WIN32
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

namespace bl{

#if defined (_UNICODE) || defined(UNICODE)
	typedef wchar_t tchar;

	#if !defined(tstring) && !defined(TSTRING_DEFINED)
		typedef std::basic_string<wchar_t> tstring;
		#define TSTRING_DEFINED
	#endif
#else
	typedef char tchar;

	#if !defined(tstring) && !defined(TSTRING_DEFINED)
		typedef std::basic_string<char> tstring;
		#define TSTRING_DEFINED
	#endif
#endif

	inline tstring& replace_all(tstring& str, const tstring& oldStr, const tstring& newStr)
	{
		for(tstring::size_type   pos(0);   pos!=tstring::npos;   pos+=newStr.length())   
		{   
			if( (pos=str.find(oldStr,pos))!=tstring::npos )   
				str.replace(pos,oldStr.length(), newStr);   
			else   break;   
		}   
		return   str;  
	}

	inline tstring format(const tchar* fmt, ...)
	{
		va_list args;
		va_start(args, fmt);

		int len = _vsctprintf(fmt, args);
		tchar* sz = new tchar[len];
		_vsntprintf(sz, len, fmt, args);

		tstring ret(sz, len);

		delete[] sz;

		va_end(args);

		return ret;
	}

	inline bool is_equal_ignore_case(const tstring& str1, const tstring& str2)
	{
		return 0 == _tcsicmp(str1.c_str(), str2.c_str());
	}

	inline bool tstr_compare_n_ignore_case(const tstring& str1, const tstring& str2, size_t count)
	{
		return 0 == _tcsnicmp(str1.c_str(), str2.c_str(), count);
	}

	inline std::vector<tstring> tokenize(const tstring& src, const tstring& tok)
	{
		std::vector<tstring> ret;

		if(src.empty() || tok.empty())
			return ret;

		tstring::size_type index=0, preIndex=0, len = 0;
		while( (index = src.find(tok, preIndex)) != tstring::npos)
		{
			if( (len=index-preIndex) !=0)
				ret.push_back(src.substr(preIndex, len));

			preIndex = index+tok.length();
		}

		tstring endStr = src.substr(preIndex);
		if(!endStr.empty())
			ret.push_back(endStr);
		
		return ret;
	}

	inline tstring tstr_left(const tstring& str, tstring::size_type count)
	{
		if(count >str.length())
			count = str.length();
		return str.substr(0, count); 
	}

	inline tstring tstr_mid(const tstring& str, tstring::size_type start, tstring::size_type count)
	{
		if(start <0)
			start = 0;
		return str.substr(start, count);
	}

	inline tstring tstr_right(const tstring& str, tstring::size_type count)
	{
		return str.substr(str.length()-count);
	}

	inline tstring& tstr_to_lower(tstring& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), _totlower);
		return str;
	}


	// Unicode convert
	inline std::string wstring_to_ansi(const wchar_t* str)
	{
#if (defined WIN32)
		int len = WideCharToMultiByte(CP_ACP, 0, str, -1, 0, 0, 0, 0);
		scoped_array<char> buf(new char[len]);
		WideCharToMultiByte(CP_ACP, 0, str, -1, buf.get(), len, 0, 0);
		return std::string(buf.get());
#endif
	}

	inline std::wstring ansi_to_wstring(const char* str)
	{
#if (defined WIN32)
		int len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
		scoped_array<wchar_t> buf(new wchar_t[len]);
		MultiByteToWideChar(CP_ACP, 0, str, -1, buf.get(), len);
		return std::wstring(buf.get());
#endif
	}

	inline std::string wstring_to_utf8(const wchar_t* str)
	{
#if (defined WIN32)
		int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, 0, 0);
		scoped_array<char> buf(new char[len]);
		WideCharToMultiByte(CP_UTF8, 0, str, -1, buf.get(), len, 0, 0);
		return std::string(buf.get());
#endif
	}

	inline std::wstring utf8_to_wstring(const char* str)
	{
#if (defined WIN32)
		int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);
		scoped_array<wchar_t> buf(new wchar_t[len]);
		MultiByteToWideChar(CP_UTF8, 0, str, -1, buf.get(), len);
		return std::wstring(buf.get());
#endif
	}


}


#ifdef WIN32
#pragma warning(pop)
#endif



#endif